﻿using System.Collections;
using System.Text;

namespace netTool.util;

/// <summary>
/// 
/// </summary>
public static class ByteExp {
    /// <summary>
    /// 数组转换为字符串,如将{0x11,0x22}转换为1122,{0xA1,0xA2}转换为A1A2
    /// </summary>
    /// <param name="bGroup"></param>
    /// <returns></returns>
    public static string ByteToString(this byte[] bGroup) {
        string temp = string.Empty;
        foreach (byte b in bGroup) {
            temp += b.ToString("X").PadLeft(2, '0');
        }
        return temp;
    }

    /// <summary>
    /// Byte类型转换为16进制字符串 所有值全部转换，字节中间有空格隔开
    /// 如：{0x01,0x02} 转换为 01 02
    /// </summary>
    /// <param name="byteBuf">欲转换的Byte类型数组</param>
    /// <param name="splitChar"></param>
    /// <returns>String类型16进制数</returns>
    public static string ByteToHexString(this byte[] byteBuf, string splitChar = " ") {
        if (byteBuf == null || byteBuf.Length == 0) return string.Empty;

        return ByteToHexString(byteBuf, 0, byteBuf.Length, splitChar);
    }

    /// <summary>
    /// Byte类型转换为16进制字符串，中间用空格断开
    /// 如：{0x01,0x02} 转换为 01 02
    /// </summary>
    /// <param name="byteBuf">欲转换的Byte类型数组</param>
    /// <param name="begin">转换的开始位置</param>
    /// <param name="len">转换的长度</param>
    /// <param name="splitChar"></param>
    /// <returns>String类型16进制数</returns>
    public static string ByteToHexString(this byte[] byteBuf, int begin, int len, string splitChar = " ") {
        if (byteBuf == null) return string.Empty;

        System.Text.StringBuilder strTmp = new System.Text.StringBuilder(len * 3);
        for (int i = 0, j = begin; i < len; i++, j++) {
            strTmp.AppendFormat("{0:X2}", byteBuf[j]);
            strTmp.Append(splitChar);
        }
        return strTmp.ToString().Trim();
    }

    /// <summary>
    /// 
    /// </summary>
    /// <param name="bGroup"></param>
    /// <returns></returns>
    public static int Byte3ToInt(this byte[] bGroup) {
        byte[] bytes = new byte[4];
        Buffer.BlockCopy(bGroup, 0, bytes, 0, 4);
        return BitConverter.ToInt32(bytes, 0);
    }

    /// <summary>
    /// 数组转换为字符串
    /// </summary>
    /// <param name="bGroup"></param>
    /// <returns></returns>
    public static string ByteToString(this byte bGroup) {
        return bGroup.ToString("X").PadLeft(2, '0'); ;
    }


    /// <summary>
    /// ASCII转换为字符串，并去掉结尾的0字节
    /// <para>如将{0x31,0x32}转换为12</para>
    /// </summary>
    /// <param name="bytes"></param>
    public static string ToStringByAscii(this byte[] bytes) {
        Encoding ascii = Encoding.ASCII;
        return ascii.GetString(bytes, 0, bytes.Length).Trim('\0');
    }

    /// <summary>
    /// Byte数组转换成 Bit数组
    /// </summary>
    /// <param name="arrByt"></param>
    /// <returns></returns>
    public static byte[] ToArrayBitByte(this byte[] arrByt) {
        BitArray bitArray = new BitArray(arrByt);
        byte[] arrByte = new byte[bitArray.Length];
        for (int i = 0; i < bitArray.Length; i++)
            arrByte[i] = bitArray[i] ? (byte)1 : (byte)0;
        return arrByte;
    }

    /// <summary>
    /// Bit数组转换成 Byte， 低字节在前，[0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00] 输出 01, data[0]下标0的为bit0
    /// </summary>
    /// <param name="data">长度小于等于8的数组，值只能是0或者1</param>
    /// <returns></returns>
    public static byte BitArrayToByteLower(this byte[] data) {
        if (data.Length > 8)
            throw new Exception("传入长度不能大于8");

        byte[] arrByte = new byte[8];
        for (int i = 0; i < data.Length; i++) {
            if (data[i] > 1)
                throw new Exception("数组中值只能是0或者1");
            arrByte[i] = data[i];
        }
        string strTemp = "";
        foreach (byte b in arrByte) {
            strTemp = b + strTemp;
        }
        return Convert.ToByte(strTemp, 2);
    }

    /// <summary>
    /// Byte转换成 Bit数组,
    /// 0x64转换位 00100110 bit[0]=0,bit[1]=0
    /// 0x01，输出为 01 00 00 00 00 00 00 00，下标为0的为bit0
    /// </summary>
    /// <param name="bt"></param>
    /// <returns></returns>
    public static byte[] ToArrayBitByte(this byte bt) {
        BitArray bitArray = new BitArray(new byte[1] { bt });
        byte[] arrByte = new byte[bitArray.Length];
        for (int i = 0; i < bitArray.Length; i++)
            arrByte[i] = bitArray[i] ? (byte)1 : (byte)0;
        return arrByte;
    }

    /// <summary>
    /// 一维数组转换成二维数组
    /// </summary>
    /// <param name="arrByt"></param>
    /// <param name="iWidth">宽</param>
    /// <param name="iHeight">高</param>
    /// <returns></returns>
    public static byte[,] ToDoubleArrayByte(this byte[] arrByt, int iWidth, int iHeight) {
        if (arrByt.Length < iWidth * iHeight)
            return null;

        byte[,] arrDblArray = new byte[iHeight, iWidth];
        for (int loopHeight = 0; loopHeight < iHeight; loopHeight++) {
            for (int loopWidth = 0; loopWidth < iWidth; loopWidth++) {
                arrDblArray[loopHeight, loopWidth] = arrByt[loopHeight * iWidth + loopWidth];
            }
        }
        return arrDblArray;
    }

    /// <summary>
    /// 对二维数组的行进行交换
    /// </summary>
    /// <param name="arrByt"></param>
    /// <returns></returns>
    public static byte[,] ToChangeArrayByte(this byte[,] arrByt) {
        #region

        //20 10
        //0, 20 - 1 - 0 = 19 >= 10
        //1, 20 - 1 - 1 = 18 >= 10
        //2, 20 - 1 - 2 = 17 >= 10
        //8, 20 - 1 - 8 = 11 >= 10
        //9, 20 - 1 - 9 = 10 >= 10
        //10, 20 - 1 - 10 = 9   10

        //21 10
        //0, 21 - 1 - 0 = 20 >= 10
        //1, 21 - 1 - 1 = 19 >= 10
        //2, 21 - 1 - 2 = 18 >= 10
        //8, 21 - 1 - 8 = 12 >= 10
        //9, 21 - 1 - 9 = 11 >= 10
        //10, 21 - 1 - 10 = 10 >=  10

        #endregion
        if (arrByt == null) {
            return null;
        }

        int iHeight = arrByt.GetLength(0);
        int iWidth = arrByt.GetLength(1);

        byte[,] arrRtn = new byte[iHeight, iWidth];

        for (int iloopHeight = 0; iloopHeight < iHeight; iloopHeight++) {
            for (int iloopWidth = 0; iloopWidth < iWidth; iloopWidth++) {
                arrRtn[iHeight - 1 - iloopHeight, iloopWidth] = arrByt[iloopHeight, iloopWidth];
            }
        }

        return arrRtn;
    }

    /// <summary>
    /// 把byte数组转换为高位4和低位4的分开的数组
    /// </summary>
    /// <param name="arrByt"></param>
    /// <param name="iWidth">宽</param>
    /// <param name="iHeight">高</param>
    /// <returns></returns>
    public static byte[] ToArray4BitByte(this byte[] arrByt, int iWidth, int iHeight) {
        byte[] arr4Array = new byte[iWidth * iHeight];
        for (int i = 0; i < arrByt.Length; i++) {
            arr4Array[i * 2] = (byte)((arrByt[i] >> 4 & 0x0f) * 15);
            if (i * 2 == iWidth * iHeight)
                break;
            arr4Array[i * 2 + 1] = (byte)((arrByt[i] & 0x0f) * 15); ;
        }
        return arr4Array;
    }

    #region 转换为二进制

    /// <summary>
    /// 将 8 位无符号整数的值转换为其等效的二进制字符串表示形式。
    /// 0x01转换为00000001
    /// <para> </para>
    /// </summary>
    /// <param name="bt"></param>
    /// <returns></returns>
    public static string ByteToSecString(this byte bt) {
        return Convert.ToString(bt, 2).PadLeft(8, '0');
    }

    /// <summary>
    /// 将 8 位无符号整数的值转换为其等效的二进制列表
    /// 如 0x64(10进制100)转换为01100100
    /// 如 0x01 转换为[1,0,0,0,0,0,0,0]，bit0 = 1
    /// </summary>
    /// <param name="bs"></param>
    /// <returns></returns>
    public static List<byte> ByteToSecList(this byte[] bs) {
        List<byte> list = new();
        foreach (var t in bs) {
            var l = ByteToSecList(t);
            list.AddRange(l);
        }

        return list;
    }

    /// <summary>
    /// 将 8 位无符号整数的值转换为其等效的二进制列表
    /// 如 0x64(10进制100)转换为01100100
    /// 如 0x01 转换为[1,0,0,0,0,0,0,0]，bit0 = 1
    /// </summary>
    /// <param name="bt"></param>
    /// <returns></returns>
    public static List<byte> ByteToSecList(this byte bt) {
        string str = Convert.ToString(bt, 2).PadLeft(8, '0');
        List<byte> list = new();
        for (int i = 0; i < str.Length; i++) {
            list.Add(Convert.ToByte(str.Substring(7 - i, 1)));
        }

        return list;
    }

    /// <summary>
    /// 将 8 位无符号整数的值转换为其等效的二进制字符串表示形式。
    /// 0D 00 输出 "0000110100000000"
    /// [0x01, 0x02] 输出 "0000000100000010"
    /// <para>如 0x64 0x64(10进制100)转换为 01100100 01100100</para>
    /// </summary>
    /// <param name="bs"></param>
    /// <returns></returns>
    public static string ByteToSecString(this byte[] bs) {
        StringBuilder sbOut = new();
        foreach (var b in bs) {
            sbOut.Append(ByteToSecString(b));
        }
        return sbOut.ToString();
    }

    /// <summary>
    /// 将 8 位无符号整数的值转换为其等效的二进制列表
    /// </summary>
    /// <param name="bt"></param>
    /// <returns></returns>
    public static List<bool> ByteToSecBoolList(this byte bt) {
        var str = Convert.ToString(bt, 2).PadLeft(8, '0');
        var list = new List<bool>();
        for (int i = 0; i < str.Length; i++) {
            list.Add(str.Substring(7 - i, 1) == "1");
        }

        return list;
    }

    #endregion 转换为二进制

    /// <summary>
    /// 计算桢校验和字节，返回一个校验字节
    /// </summary>
    /// <param name="userData">校验数据</param>
    /// <returns></returns>
    public static byte GetVerifyFramesSum(this byte[] userData) {
        int sum = 0;
        foreach (byte b in userData) {
            sum += Convert.ToInt32(b);
        }
        int rem;
        Math.DivRem(sum, 256, out rem);
        return Convert.ToByte(rem);
    }

    /// <summary>
    /// 计算桢校验和字节，每两个字节转成无符号的累加，取累加和转成byte数组的最后四个字节
    /// </summary>
    /// <param name="data">校验数据</param>
    /// <returns></returns>
    public static byte[] GetSumUInt32(this byte[] data) {
        UInt64 sum = 0;
        // 每两个字节组成一个ushort进行累加
        for (int i = 0; i < data.Length; i += 2) {
            // 低字节在前
            byte low = data[i];
            byte high = i + 1 < data.Length ? data[i + 1] : (byte)0; // 奇数长度补零
            ushort value = (ushort)((high << 8) | low);
            sum += value;
        }
        byte[] ret = new byte[4];
        byte[] bsTemp = BitConverter.GetBytes(sum);
        Array.Copy(bsTemp, 0, ret, 0, ret.Length);
        return ret;
    }


    /// <summary>
    /// CRC  XMODEM校验模式
    /// </summary>
    /// <param name="data">数据</param>
    /// <returns></returns>
    public static UInt16 CRCXMODEM(byte[] data) {
        UInt32 i = 0;
        UInt16 crc = 0;
        for (i = 0; i < data.Length; i++) {
            crc = UpdateCRC16(crc, data[i]);
        }
        crc = UpdateCRC16(crc, 0);
        crc = UpdateCRC16(crc, 0);
        return (UInt16)(crc);
    }

    /// <summary>
    /// 更新RCR16校验
    /// </summary>
    /// <param name="crcIn"></param>
    /// <param name="bytee"></param>
    /// <returns></returns>
    private static UInt16 UpdateCRC16(UInt16 crcIn, byte bytee) {
        UInt32 crc = crcIn;
        UInt32 ins = (UInt32)bytee | 0x100;
        do {
            crc <<= 1;
            ins <<= 1;
            if ((ins & 0x100) == 0x100) {
                ++crc;
            }
            if ((crc & 0x10000) == 0x10000) {
                crc ^= 0x1021;
            }
        }
        while (!((ins & 0x10000) == 0x10000));
        return (UInt16)crc;
    }

    /// <summary>
    /// CRC-16/MODBUS校验算法：多项式0x8005,初始值0xffff,异或值0x0000;
    /// (举例55 AA 01 00 62 A1 E9)(CRC值E9A1)；
    /// </summary>
    /// <param name="src"></param>
    /// <param name="startIndex"></param>
    /// <param name="len"></param>
    /// <returns></returns>
    public static UInt16 Crc16Modbus(byte[] src, int startIndex, int len) {
        // 注意: 这里是0x8005的反转
        ushort polynomial = 0xA001;
        if (src == null || src.Length == 0) return 0;

        byte[] data = new byte[len];
        Array.Copy(src, startIndex, data, 0, len);

        ushort crc = 0xFFFF; // 初始值

        foreach (byte b in data) {
            crc ^= b;
            for (int i = 0; i < 8; ++i) {
                if ((crc & 0x0001) != 0) {
                    crc = (ushort)((crc >> 1) ^ polynomial);
                }
                else {
                    crc >>= 1;
                }
            }
        }

        return crc;
    }



    /// <summary>
    /// 将一个byte数组分割成多个固定大小的byte数组列表。每组固定字节数，如果有未使用的byte填充0xff
    /// </summary>
    /// <param name="source">源byte数组。</param>
    /// <returns>包含分割后的byte数组的列表。</returns>
    public static List<byte[]> SplitIntoByteGroups(this byte[] source) {
        var result = new List<byte[]>();
        int length = source.Length;
        byte count = 0;
        for (int i = 0; i < length; i += 7) {
            count++;
            // 计算当前分组的实际大小，确保不超过剩余元素数量，最后一组为剩余实际大小
            int currentGroupSize = Math.Min(7, length - i);

            // 创建并添加一个新的byte数组到列表中。每组固定字节数，如果有未使用的byte填充0xff
            byte[] group = new byte[8];
            group[0] = count;   //当前第几包
            Array.Copy(source, i, group, 1, currentGroupSize);
            // 如果当前分组不足 groupSize 个元素，用 0xff 填充剩余位置
            if (currentGroupSize < 7) {
                for (int j = currentGroupSize; j < 7; j++) {
                    group[j + 1] = 0xff;
                }
            }
            result.Add(group);
        }

        return result;
    }

    /// <summary>
    /// 合并两个数组，得到一个新的数组。第一个数组的数据放前面，第二个数组的数据放后面
    /// </summary>
    /// <param name="array1"></param>
    /// <param name="array2"></param>
    /// <returns></returns>
    public static byte[] MergeByteArrays(byte[] array1, byte[] array2) {
        // 创建一个新的byte数组，长度为两个输入数组的长度之和
        byte[] mergedArray = new byte[array1.Length + array2.Length];

        // 将第一个数组的内容复制到新数组中
        Buffer.BlockCopy(array1, 0, mergedArray, 0, array1.Length);

        // 将第二个数组的内容复制到新数组中，接在第一个数组的后面
        Buffer.BlockCopy(array2, 0, mergedArray, array1.Length, array2.Length);

        return mergedArray;
    }

    /// <summary>
    /// 截取数组指定长度到新数组
    /// </summary>
    /// <param name="source"></param>
    /// <param name="startIndex"></param>
    /// <param name="length"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public static byte[] SubArray(byte[] source, int startIndex, int length) {
        // 检查输入参数是否有效
        if (source == null)
            throw new ArgumentNullException(nameof(source), "源数组不能为空");

        if (startIndex < 0 || startIndex >= source.Length)
            throw new ArgumentOutOfRangeException(nameof(startIndex), "起始索引超出范围");

        if (length < 0 || startIndex + length > source.Length)
            throw new ArgumentOutOfRangeException(nameof(length), "截取长度超出范围");

        // 创建一个新的byte数组来存储截取的内容
        byte[] subArray = new byte[length];

        // 使用Buffer.BlockCopy复制数据
        Buffer.BlockCopy(source, startIndex, subArray, 0, length);

        return subArray;
    }

    /// <summary>
    /// 从数组左侧截取指定长度的byte数组
    /// </summary>
    /// <param name="source"></param>
    /// <param name="length"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public static byte[] SubLeft(byte[] source, int length) {
        return SubArray(source, 0, length);
    }

    /// <summary>
    /// 从数组右侧截取指定长度的数组
    /// </summary>
    /// <param name="source"></param>
    /// <param name="length"></param>
    /// <returns></returns>
    /// <exception cref="ArgumentNullException"></exception>
    /// <exception cref="ArgumentOutOfRangeException"></exception>
    public static byte[] SubRight(byte[] source, int length) {
        return SubArray(source, source.Length - length, length);
    }


    /// <summary>
    /// 随机产生64位无符号数字
    /// </summary>
    /// <returns></returns>
    public static uint GenerateRandomUInt() {
        byte[] buffer = GenerateRandomByte(4);
        // Make sure the result is treated as an unsigned number
        return BitConverter.ToUInt32(buffer, 0);
    }

    /// <summary>
    /// 随机产生64位无符号数字
    /// </summary>
    /// <returns></returns>
    public static ulong GenerateRandomUlong() {
        byte[] buffer = GenerateRandomByte(8);
        // Make sure the result is treated as an unsigned number
        return BitConverter.ToUInt64(buffer, 0);
    }

    /// <summary>
    /// 随机产生64位无符号数字
    /// </summary>
    /// <returns></returns>
    public static byte[] GenerateRandomByte(int len) {
        byte[] buffer = new byte[len]; // 8 bytes for an unsigned long (ulong)
        new Random().NextBytes(buffer);
        // Make sure the result is treated as an unsigned number
        return buffer;
    }

    /// <summary>
    /// byte数组左侧补零，长度不够时左侧补零，超出时不补
    /// </summary>
    /// <param name="array"></param>
    /// <param name="len"></param>
    /// <returns></returns>
    public static byte[] PadLeft(this byte[] array, int len) {
        if (array.Length >= len) return array;

        byte[] bsTemp = new byte[len];
        Array.Copy(array,0, bsTemp,len - array.Length, array.Length);
        return bsTemp;
    }

    /// <summary>
    /// 异或运算
    /// </summary>
    /// <param name="array1">数组一</param>
    /// <param name="array2">数组二</param>
    /// <returns></returns>
    public static byte[] Xor(this byte[] array1, byte[] array2) {
        // 确定最小长度
        int minLength = Math.Min(array1.Length, array2.Length);
        byte[] xorResult = new byte[minLength];

        for (int i = 0; i < minLength; i++) {
            xorResult[i] = (byte)(array1[i] ^ array2[i]);
        }

        return xorResult;
    }

    /// <summary>
    /// 通讯数据加密
    /// </summary>
    /// <param name="data"></param>
    /// <param name="key"></param>
    /// <exception cref="ArgumentException"></exception>
    public static void Encrypt(this byte[] data, byte key = 0xA3) {
        byte bTemp1 = data[0];
        ushort loopCount = (ushort)((key & 0x0F) + 1);

        // 处理第一个元素
        for (ushort j = 0; j < loopCount; j++) {
            data[0] = (byte)(((data[0] >> 3) | (data[0] << 5)) ^ key);
        }

        // 处理剩余元素
        for (ushort i = 1; i < data.Length; i++) {
            byte bTemp2 = data[i];
            for (ushort j = 0; j < loopCount; j++) {
                data[i] = (byte)(((data[i] >> 3) | (data[i] << 5)) ^ bTemp1 ^ data[0]);
            }
            bTemp1 = bTemp2;
        }
    }

    /// <summary>
    /// 解密
    /// </summary>
    /// <param name="data"></param>
    /// <param name="key"></param>
    /// <exception cref="ArgumentException"></exception>
    public static void Decrypt(this byte[] data, byte key = 0xA3) {
        byte bTemp1 = data[0];
        ushort loopCount = (ushort)((key & 0x0F) + 1);

        // 解密第一个元素
        for (ushort j = 0; j < loopCount; j++) {
            data[0] ^= key;
            int x = ((data[0] >> 5) | (data[0] << 3));
            data[0] = (byte)(((data[0] >> 5) | (data[0] << 3)) & 0xFF);
        }

        // 解密剩余元素
        for (ushort i = 1; i < data.Length; i++) {
            for (ushort j = 0; j < loopCount; j++) {
                data[i] ^= bTemp1;
                data[i] ^= data[i - 1];
                //Trace.WriteLine($"{((data[i] >> 5) | (data[i] << 3)):X4}");
                data[i] = (byte)(((data[i] >> 5) | (data[i] << 3)) & 0xFF);
            }
        }
    }




} // class end